package com.zpself.module.JDK8新功能.Optional;

import com.zpself.module.JDK8新功能.Optional.entity.User;
import org.junit.Test;

import java.util.Optional;

/**
 * @author By ZengPeng
 * @Description Optional 类是一个容器类。在之前我们通常用 null 来表达一个值不存在，现在可以用 Optional 更好的表达值存在或者不存在。
 *               这样的目的，主要就是为了防止出现空指针异常 NullPointerException 。
 * @date in  2021/3/1 20:15
 * @Modified By
 */
public class TestOptional {

    @Test
    //1.与 isPresent 方法不同， ifPresent 方法是我们推荐使用的。如可以这样判空：
    public  void ifPresent(){
        Optional<User> user = Optional.ofNullable(new User());
        //ifPresent  接收一个消费函数
        user.ifPresent(System.out::println);

        //不要用下边这种
        if (user.isPresent()) {
            System.out.println(user.get());
        }
    }


    @Test
    //2.orElse  orElseGet 这两个方法都是当值不存在时，用于返回一个默认值。如user对象为null时，返回默认值。
    //当user对象不为null时，orElse依然会创建User对象，而orElseGet不会创建。所以orElseGet更好
    public  void orElse(){
        User user = new User();
        System.out.println("orElse调用");
        User user1 = Optional.ofNullable(user).orElse(createUser());
        System.out.println("orElseGet调用");
        User user2 = Optional.ofNullable(user).orElseGet(() -> createUser());
    }
    private User createUser() {
        //此处打印，是为了查看orElse和orElseGet的区别
        System.out.println("createUser...");
        return new User();
    }



    @Test
    //3.orElseThrow  当值为null，可以返回自定义异常。
    public  void orElseThrow(){
        User user = null;
        Optional.ofNullable(user).orElseThrow(NullPointerException::new);
    }

    @Test
    //4.map  map类似 Stream 的 map方法。处理完之后，返回的还是一个 Optional 对象，所以可以做链式调用。
    public  void map(){
        User user = new User();
        String name = Optional.of(user).map(User::getName)
                .orElse("佚名");
        System.out.println(name);

        //先获取address对象
        //中间所有可能出现空指针的情况，Optional都会规避。因为 value!=null这个操作已经被封装了。
        // 而且在不同的处理阶段，Optional 会自动帮我们包装不同类型的值。
        Optional<User> user2 = Optional.of(user);
        String address=  user2.map((u)->u.getAddress())
                //再获取details值，
                .map(e -> e.getDetails())
                //若detail为null，则返回一个默认值
                .orElse("地址信息未填写");
    }

    @Test
    //5.flatMap  乍看这个方法和 map 没什么区别。其实，它们的区别就在于传入的 mapper参数的第二个泛型。
    public  void flatMap(){
        User user = new User();
        String name = Optional.of(user).flatMap((u) -> this.getUserName(u))
                .orElse("佚名");
        System.out.println(name);
    }
    //把用户名包装成Optional<String>，作为 Function 接口的返回值，以适配flatMap
    private Optional<String> getUserName(User user){
        return Optional.ofNullable(user.getName());
    }


    @Test
    //6.filter 是用来根据条件过滤的，如果符合条件，就返回当前 Optional 对象本身，否则返回一个值为 null的 Optional 对象。
    public  void filter(){
        User user = new User();
        //由于user没有设置 name，所以返回一个值为 null 的 optionalUser
        Optional<User> optionalUser = Optional.of(user).filter((u) -> this.getUserName(u).isPresent());
        //由于值为 null，所以get方法抛出异常 NoSuchElementException
        optionalUser.get();
    }
}
